// Copyright 2022 The Molego Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package logger

import (
	"fmt"
	"os"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	lumberjackv2 "gopkg.in/natefinch/lumberjack.v2"
)

var (
	Level = zap.DebugLevel
)

var (
	Log  *zap.Logger        // log to file and console
	Logf *zap.Logger        // log to file only
	Logc *zap.Logger        // log to console only
	Sug  *zap.SugaredLogger // log by Sugar to file and console
	Sugf *zap.SugaredLogger // log by Sugar to file only
	Sugc *zap.SugaredLogger // log by Sugar to console only
)

func NewEncoderConfig() zapcore.EncoderConfig {
	return zapcore.EncoderConfig{
		// Keys can be anything except the empty string.
		TimeKey:        "T",
		LevelKey:       "L",
		NameKey:        "N",
		CallerKey:      "C",
		MessageKey:     "M",
		StacktraceKey:  "S",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeTime:     TimeEncoder,
		EncodeDuration: zapcore.StringDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
}

func TimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}

// 日志组件初始化
func InitLog() {
	syncerFile := zapcore.AddSync(&lumberjackv2.Logger{
		Filename:   "log/molego.log", // 日志文档路径
		MaxSize:    10,               // 每个日志文档保存的最大尺寸 单位：MB
		MaxBackups: 30,               // 日志文档最多保存多少个备份
		MaxAge:     30,               // 文档最多保存多少天
		Compress:   true,             // 是否压缩
	})
	syncerConsole := zapcore.AddSync(os.Stdout)

	// core to file and console
	core := zapcore.NewCore(
		zapcore.NewConsoleEncoder(NewEncoderConfig()),
		zapcore.NewMultiWriteSyncer(syncerConsole, syncerFile),
		Level,
	)

	// coref to file only
	coref := zapcore.NewCore(
		zapcore.NewConsoleEncoder(NewEncoderConfig()),
		zapcore.NewMultiWriteSyncer(syncerFile),
		Level,
	)

	// corec to console only
	corec := zapcore.NewCore(
		zapcore.NewConsoleEncoder(NewEncoderConfig()),
		zapcore.NewMultiWriteSyncer(syncerConsole),
		Level,
	)
	Log = zap.New(core, zap.AddCaller())
	Logf = zap.New(coref, zap.AddCaller())
	Logc = zap.New(corec, zap.AddCaller())
	Sug = Log.Sugar()
	Sugf = Logf.Sugar()
	Sugc = Logc.Sugar()

	// dosomething()
}

// 测试一下
func dosomething() {
	Log.Info("InfoLogger to file and console")
	Log.Error("ErrorLogger to file and console")
	Log.Debug("DebugLogger to file and console")
	Log.Warn("WarnLogger to file and console")

	Logf.Info("InfoLogger to file only")
	Logf.Error("ErrorLogger to file only")
	Logf.Debug("DebugLogger to file only")
	Logf.Warn("WarnLogger to file only")

	Logc.Info("InfoLogger to console only")
	Logc.Error("ErrorLogger to console only")
	Logc.Debug("DebugLogger to console only")
	Logc.Warn("WarnLogger to console only")

	Sug.Warnf("Sug.Warnf: %s %v %T %d %T", "zap-sugar", "zap-sugar", "zap-sugar", 123, 123)
	Sug.Info("Sug println ", 123, "456")
	for i := 0; i < 2; i++ {
		//结构化日志输出，即字段和消息
		//字段用来结构化输出错误相关的上下文环境，而消息简明扼要的阐述错误本身
		Logc.Info(fmt.Sprint("test log", i), zap.Int("line", 47))
		Logc.Debug(fmt.Sprint("debug log", i), zap.ByteString("level", nil))
		Logc.Info(fmt.Sprint("Info log", i), zap.String("level", `{"a":"4","b":"5"}`))
		Logc.Warn(fmt.Sprint("Warn log", i), zap.String("level", `{"a":"7","b":"8"}`))
		Logc.Error(fmt.Sprint("Error log", i), zap.String("level", `{"a":"7","b":"8"}`))
		// 用户不存在的错误消息
		Logc.Error("User does not exist", zap.String("Name", "namestring"))
		Sug.Debugf("Sugf.Debugf world : %s", "zap-sugar")
		Sug.Errorf("Sugf.Errorf world : %v", "zap-sugar")
		Sug.Infof("Sugf.Infof world : %T", "zap-sugar")
		Sug.Warnf("Sugf.Warnf world : %v %d", "zap-sugar", 123)
	}
}
